#!/bin/bash

# 脚本名称: kibana_fix.sh
# 功能描述: 诊断和修复Kibana服务问题
# 使用方法: sudo bash kibana_fix.sh

# 检查是否以root权限运行
if [ "$(id -u)" -ne 0 ]; then
    echo "错误: 请使用root权限运行此脚本"
    exit 1
fi

# 日志文件路径
LOG_FILE="/var/log/kibana_fix.log"

# 记录日志函数
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}

# 检查系统资源函数
check_system_resources() {
    log "检查系统资源..."
    
    # 检查内存使用情况
    log "检查内存使用情况..."
    mem_info=$(free -h)
    log "内存使用情况:"
    echo "$mem_info" >> $LOG_FILE
    
    # 检查可用内存是否低于1GB
    available_mem=$(free -m | awk '/^Mem:/ {print $7}')
    if [ $available_mem -lt 1024 ]; then
        log "警告: 可用内存低于1GB，这可能导致Kibana性能问题"
        log "尝试释放系统缓存..."
        sync && echo 3 > /proc/sys/vm/drop_caches
        log "系统缓存已释放"
    else
        log "可用内存充足: ${available_mem}MB"
    fi
    
    # 检查磁盘空间
    log "检查磁盘空间..."
    disk_info=$(df -h)
    log "磁盘使用情况:"
    echo "$disk_info" >> $LOG_FILE
    
    # 检查Kibana数据目录所在分区的可用空间
    kibana_data_dir="/data/kibana"
    if [ -d "$kibana_data_dir" ]; then
        kibana_disk_free=$(df -h "$kibana_data_dir" | awk 'NR==2 {print $4}')
        log "Kibana数据目录可用空间: $kibana_disk_free"
    fi
    
    # 检查CPU负载
    log "检查CPU负载..."
    cpu_load=$(uptime | awk -F'load average:' '{print $2}')
    log "CPU负载: $cpu_load"
}

# 检查JVM配置函数
check_jvm_config() {
    log "检查JVM配置..."
    
    # 检查Kibana JVM配置文件
    if [ -f "/etc/kibana/jvm.options" ]; then
        log "Kibana JVM配置内容:"
        cat /etc/kibana/jvm.options >> $LOG_FILE
        
        # 检查JVM堆大小设置
        heap_min=$(grep -E "^-Xms" /etc/kibana/jvm.options | awk '{print $1}')
        heap_max=$(grep -E "^-Xmx" /etc/kibana/jvm.options | awk '{print $1}')
        log "JVM堆设置: 最小=$heap_min, 最大=$heap_max"
        
        # 如果堆设置不合理，尝试修复
        if [[ "$heap_min" != "-Xms1g" || "$heap_max" != "-Xmx1g" ]]; then
            log "JVM堆设置不是推荐值，尝试修复..."
            sed -i 's/^-Xms[0-9].*/\-Xms1g/' /etc/kibana/jvm.options
            sed -i 's/^-Xmx[0-9].*/\-Xmx1g/' /etc/kibana/jvm.options
            log "JVM堆设置已修复为推荐值"
        fi
    else
        log "未找到Kibana JVM配置文件"
    fi
}

# 检查网络连接函数
check_network_connectivity() {
    log "执行网络连接测试..."
    
    # 获取Kibana配置中的Elasticsearch主机
    if [ -f "/etc/kibana/kibana.yml" ]; then
        es_hosts=$(grep "elasticsearch.hosts" /etc/kibana/kibana.yml | awk -F'[\[\]]' '{print $2}' | tr -d '"')
        if [ -z "$es_hosts" ]; then
            es_hosts="http://localhost:9200"
            log "未在配置中找到Elasticsearch主机，使用默认值: $es_hosts"
        else
            log "配置中的Elasticsearch主机: $es_hosts"
        fi
        
        # 从es_hosts中提取主机名和端口
        es_host=$(echo $es_hosts | sed -E 's|http(s)?://||g' | awk -F':' '{print $1}')
        es_port=$(echo $es_hosts | sed -E 's|http(s)?://||g' | awk -F':' '{print $2}')
        if [ -z "$es_port" ]; then
            es_port="9200"
        fi
        
        # 测试到Elasticsearch的TCP连接
        log "测试到Elasticsearch($es_host:$es_port)的TCP连接..."
        if nc -z -w5 $es_host $es_port 2>/dev/null; then
            log "TCP连接到Elasticsearch成功"
        else
            log "错误: 无法建立到Elasticsearch的TCP连接"
            log "检查Elasticsearch是否运行以及网络连接是否正常"
        fi
        
        # 测试Elasticsearch API响应
        log "测试Elasticsearch API响应..."
        es_response=$(curl -s -o /dev/null -w "%{http_code}" "$es_hosts")
        if [ "$es_response" = "200" ]; then
            log "Elasticsearch API响应正常(HTTP 200)"
        else
            log "警告: Elasticsearch API响应异常(HTTP $es_response)"
        fi
    else
        log "警告: 找不到Kibana配置文件，无法确定Elasticsearch主机"
    fi
    
    # 测试Kibana端口是否已被占用
    log "检查Kibana端口(5601)是否已被占用..."
    if netstat -tuln | grep -q ":5601 "; then
        log "Kibana端口(5601)已被占用"
        port_process=$(netstat -tulnp | grep ":5601 " | awk '{print $7}')
        log "占用端口的进程: $port_process"
    else
        log "Kibana端口(5601)未被占用"
    fi
}

# 分析Kibana日志函数
analyze_kibana_logs() {
    log "分析Kibana日志..."
    
    if [ -f "/var/log/kibana/kibana.log" ]; then
        # 检查常见错误模式
        log "检查常见错误模式..."
        
        # 检查连接错误
        if grep -q "Unable to connect to Elasticsearch" /var/log/kibana/kibana.log; then
            log "发现错误: 无法连接到Elasticsearch"
            log "建议: 确保Elasticsearch正在运行，并检查Kibana配置中的elasticsearch.hosts设置"
        fi
        
        # 检查权限错误
        if grep -q "permission denied" /var/log/kibana/kibana.log; then
            log "发现错误: 权限被拒绝"
            log "建议: 检查Kibana数据目录的权限设置"
        fi
        
        # 检查端口绑定错误
        if grep -q "address already in use" /var/log/kibana/kibana.log; then
            log "发现错误: 地址已被使用"
            log "建议: 检查端口5601是否已被其他进程占用"
        fi
        
        # 检查内存错误
        if grep -q "JavaScript heap out of memory" /var/log/kibana/kibana.log; then
            log "发现错误: JavaScript堆内存不足"
            log "建议: 增加Node.js内存限制或优化Kibana配置"
        fi
        
        # 提取最近的错误信息
        log "最近的错误信息:"
        grep -i "error" /var/log/kibana/kibana.log | tail -n 10 >> $LOG_FILE
    else
        log "警告: 找不到Kibana日志文件"
    fi
}

# 修复Kibana配置函数
fix_kibana_config() {
    log "检查并修复Kibana配置..."
    
    if [ -f "/etc/kibana/kibana.yml" ]; then
        # 备份原配置文件
        cp /etc/kibana/kibana.yml /etc/kibana/kibana.yml.bak.$(date +%Y%m%d%H%M%S)
        log "已备份原配置文件"
        
        # 检查并修复基本配置
        if ! grep -q "^server.host:" /etc/kibana/kibana.yml; then
            log "添加server.host配置..."
            echo "server.host: \"0.0.0.0\"" >> /etc/kibana/kibana.yml
        fi
        
        if ! grep -q "^server.port:" /etc/kibana/kibana.yml; then
            log "添加server.port配置..."
            echo "server.port: 5601" >> /etc/kibana/kibana.yml
        fi
        
        if ! grep -q "^elasticsearch.hosts:" /etc/kibana/kibana.yml; then
            log "添加elasticsearch.hosts配置..."
            echo "elasticsearch.hosts: [\"http://localhost:9200\"]" >> /etc/kibana/kibana.yml
        fi
        
        if ! grep -q "^path.data:" /etc/kibana/kibana.yml; then
            log "添加path.data配置..."
            echo "path.data: /data/kibana" >> /etc/kibana/kibana.yml
        fi
        
        log "Kibana配置已检查并修复"
    else
        log "警告: 找不到Kibana配置文件，创建新配置..."
        mkdir -p /etc/kibana
        cat > /etc/kibana/kibana.yml << EOF
# ======================== Kibana Configuration =========================
server.host: "0.0.0.0"
server.port: 5601
elasticsearch.hosts: ["http://localhost:9200"]
path.data: /data/kibana
EOF
        log "已创建新的Kibana配置文件"
    fi
}

# 检查Kibana服务状态
log "检查Kibana服务状态..."
kibana_status=$(systemctl status kibana)
log "Kibana服务详细状态:"
echo "$kibana_status" >> $LOG_FILE

# 检查Kibana日志
log "检查Kibana日志..."
if [ -f "/var/log/kibana/kibana.log" ]; then
    log "Kibana日志内容(最后50行):"
    tail -n 50 /var/log/kibana/kibana.log >> $LOG_FILE
else
    log "警告: 找不到Kibana日志文件"
fi

# 检查Kibana配置
log "检查Kibana配置..."
if [ -f "/etc/kibana/kibana.yml" ]; then
    log "Kibana配置内容:"
    cat /etc/kibana/kibana.yml >> $LOG_FILE
else
    log "警告: 找不到Kibana配置文件"
fi

# 检查系统资源
check_system_resources

# 检查JVM配置
check_jvm_config

# 检查Elasticsearch连接
log "检查Elasticsearch连接..."
if curl -s "http://localhost:9200" > /dev/null; then
    log "Elasticsearch连接正常"
else
    log "警告: 无法连接到Elasticsearch，这可能是Kibana无法启动的原因"
    log "尝试重启Elasticsearch..."
    systemctl restart elasticsearch
    sleep 30
    if curl -s "http://localhost:9200" > /dev/null; then
        log "Elasticsearch重启后连接正常"
    else
        log "错误: 重启后仍无法连接到Elasticsearch"
        log "检查Elasticsearch服务状态..."
        es_status=$(systemctl status elasticsearch)
        echo "$es_status" >> $LOG_FILE
        log "检查Elasticsearch日志..."
        if [ -f "/var/log/elasticsearch/elk-cluster.log" ]; then
            tail -n 50 /var/log/elasticsearch/elk-cluster.log >> $LOG_FILE
        fi
    fi
fi

# 执行网络连接测试
check_network_connectivity

# 检查防火墙设置
log "检查防火墙设置..."
if systemctl is-active firewalld &>/dev/null; then
    if firewall-cmd --list-ports | grep -q "5601/tcp"; then
        log "Kibana端口(5601)已在防火墙中开放"
    else
        log "警告: Kibana端口(5601)未在防火墙中开放"
        log "开放Kibana端口..."
        firewall-cmd --permanent --add-port=5601/tcp
        firewall-cmd --reload
        log "防火墙已更新"
    fi
    
    # 检查Elasticsearch端口
    if ! firewall-cmd --list-ports | grep -q "9200/tcp"; then
        log "警告: Elasticsearch端口(9200)未在防火墙中开放"
        log "开放Elasticsearch端口..."
        firewall-cmd --permanent --add-port=9200/tcp
        firewall-cmd --reload
        log "防火墙已更新"
    fi
else
    log "防火墙未运行"
fi

# 检查SELinux设置
log "检查SELinux设置..."
if command -v getenforce &>/dev/null; then
    selinux_status=$(getenforce)
    log "SELinux状态: $selinux_status"
    
    if [ "$selinux_status" = "Enforcing" ]; then
        log "SELinux处于强制模式，可能会影响Kibana运行"
        log "临时设置SELinux为宽容模式..."
        setenforce 0
        log "SELinux已设置为宽容模式"
        
        # 永久设置SELinux为宽容模式
        if [ -f "/etc/selinux/config" ]; then
            log "永久设置SELinux为宽容模式..."
            sed -i 's/SELINUX=enforcing/SELINUX=permissive/g' /etc/selinux/config
            log "SELinux已永久设置为宽容模式，重启后生效"
        fi
    fi
else
    log "未检测到SELinux工具"
fi

# 检查Kibana数据目录权限
log "检查Kibana数据目录权限..."
if [ -d "/data/kibana" ]; then
    log "设置Kibana数据目录权限..."
    chown -R kibana:kibana /data/kibana
    chmod -R 755 /data/kibana
    log "数据目录权限已设置"
else
    log "创建Kibana数据目录..."
    mkdir -p /data/kibana
    chown -R kibana:kibana /data/kibana
    chmod -R 755 /data/kibana
    log "数据目录已创建并设置权限"
fi

# 分析Kibana日志
analyze_kibana_logs

# 修复Kibana配置
fix_kibana_config

# 重启Kibana服务
log "重启Kibana服务..."
systemctl restart kibana
sleep 60  # 给Kibana足够的启动时间

# 再次检查Kibana服务状态
kibana_status=$(systemctl is-active kibana)
log "重启后Kibana服务状态: $kibana_status"

if [ "$kibana_status" = "active" ]; then
    log "Kibana服务已成功启动!"
    SERVER_IP=$(hostname -I | awk '{print $1}')
    log "Kibana可通过 http://${SERVER_IP}:5601 访问"
    
    # 验证Kibana是否可访问
    log "验证Kibana是否可访问..."
    if curl -s -o /dev/null -w "%{http_code}" "http://localhost:5601/app/home" | grep -q "200\|302"; then
        log "Kibana网页可正常访问"
    else
        log "警告: Kibana网页无法访问，但服务已启动"
        log "可能需要更长时间初始化，请稍后再试"
    fi
else
    log "Kibana服务启动失败，请检查日志获取详细信息"
    log "尝试以下故障排除步骤:"
    log "1. 检查Kibana日志: /var/log/kibana/kibana.log"
    log "2. 检查系统日志: journalctl -xe"
    log "3. 确保Elasticsearch正常运行"
    log "4. 检查Kibana配置文件中的elasticsearch.hosts设置"
    log "5. 检查网络连接和防火墙设置"
    log "6. 检查系统资源(内存、CPU、磁盘空间)"
    log "7. 检查JVM配置是否正确"
    
    # 尝试使用journalctl获取更多信息
    log "Kibana服务日志(journalctl):"
    journalctl -u kibana --no-pager -n 50 >> $LOG_FILE
    
    # 尝试以调试模式启动Kibana
    log "尝试以调试模式启动Kibana..."
    log "运行: sudo -u kibana /usr/share/kibana/bin/kibana --debug"
    log "这将在前台启动Kibana并显示详细日志，可以帮助诊断问题"
    log "按Ctrl+C可以停止调试模式"
 fi

# 检查网络连接
log "检查网络连接..."
netstat -tlpn | grep 5601 >> $LOG_FILE

# 总结诊断结果
log "===== 诊断摘要 ====="
log "系统资源检查: 完成"
log "JVM配置检查: 完成"
log "网络连接测试: 完成"
log "Elasticsearch连接: $(curl -s -o /dev/null -w "%{http_code}" "http://localhost:9200" 2>/dev/null || echo "失败")"
log "Kibana配置检查: 完成"
log "Kibana日志分析: 完成"
log "Kibana服务状态: $kibana_status"

log "诊断完成，请查看日志文件 $LOG_FILE 获取详细信息"